package service

import (
	"context"
	"errors"
	"fmt"
	"github.com/star-find-cloud/star-chat/pkg/jwt"
	log "github.com/star-find-cloud/star-chat/pkg/logger"
	"github.com/star-find-cloud/star-chat/user/domain"
	"github.com/star-find-cloud/star-chat/utils"
	"time"
)

type UserServiceImpl struct {
	repo domain.UserRepo
}

func NewUserServiceImpl(repo domain.UserRepo) *UserServiceImpl {
	return &UserServiceImpl{repo: repo}
}

func (s *UserServiceImpl) Create(ctx context.Context, user *domain.User) (int64, error) {
	return s.repo.Create(ctx, user)
}

func (s *UserServiceImpl) Register(ctx context.Context, user *domain.User) (string, int64, error) {
	phoneExist, err := s.IsExistsByPhone(ctx, user.Phone)
	if err != nil {
		log.AppLogger.Errorf("an error occurred in the user repo, err: %v", err)
		return "", 0, err
	}

	if !utils.VerifyEmail(user.Email) {
		return "", 0, errors.New("email format is incorrect")
	}

	emailExist, err := s.IsExistsByEmail(ctx, user.Email)
	if err != nil {
		log.AppLogger.Errorf("an error occurred in the user repo, err: %v", err)
		return "", 0, err
	}
	if phoneExist || emailExist {
		return "", 0, errors.New("phone or email already exists")
	}
	safePasswd, err := utils.BcryptPassword(user.Password)
	if err != nil {
		log.AppLogger.Errorf("password encryption failed: %v", err)
		return "", 0, fmt.Errorf("password encryption failed: %v", err)
	}
	user.Password = safePasswd

	id, err := s.repo.Create(ctx, user)
	if err != nil {
		log.AppLogger.Errorf("create user metadata failed: %v", err)
		return "", 0, err
	}

	fmt.Println("用户注册模块, token 需要在权限系统完善后进行修改, 相关代码在 user_service_impl")
	token, err := jwt.GenerateToken(id, 1)
	return token, id, err
}

func (s *UserServiceImpl) Get(ctx context.Context, id int64) (*domain.User, error) {
	return s.repo.GetAll(ctx, id)
}

func (s *UserServiceImpl) GetByID(ctx context.Context, id int64) (*domain.User, error) {
	if id < 1000000 {
		return nil, errors.New("invalid user id")
	}
	return s.repo.GetByID(ctx, id)
}

func (s *UserServiceImpl) GetByEmail(ctx context.Context, email string) (*domain.User, error) {
	result := utils.VerifyEmail(email)
	if !result {
		return nil, errors.New("email format is incorrect")
	}
	return s.repo.GetByEmail(ctx, email)
}

func (s *UserServiceImpl) GetByPhone(ctx context.Context, countryCode, phone int64) (*domain.User, error) {
	if phone < 10000 {
		return nil, errors.New("invalid phone number")
	}
	return s.repo.GetByPhone(ctx, countryCode, phone)
}

func (s *UserServiceImpl) Login(ctx context.Context, loginTypeCode, id, phone, countryCode int64, email, password string) (string, error) {
	switch loginTypeCode {
	case domain.LoginByID:
		return s.LoginByID(ctx, id, password)
	case domain.LoginByEmail:
		return s.LoginByEmail(ctx, email, password)
	case domain.LoginByPhone:
		return s.LoginByPhone(ctx, countryCode, phone, password)
	}
	return "", errors.New("login error")
}

func (s *UserServiceImpl) LoginByID(ctx context.Context, id int64, password string) (string, error) {
	if id < 1000000 {
		return "", errors.New("invalid user id")
	}
	hashPasswd, err := utils.BcryptPassword(password)
	if err != nil {
		log.AppLogger.Errorf("password encryption failed: %v", err)
		return "", errors.New("your password is invalid")
	}
	result, err := s.repo.CheckPasswordByID(ctx, id, hashPasswd)
	if err != nil {
		log.AppLogger.Errorf("an error occurred in the user repo, err: %v", err)
		return "", err
	}
	if !result {
		return "", errors.New("your account or password is incorrect")
	}
	token, err := jwt.GenerateToken(id, 1)
	if err != nil {
		log.AppLogger.Errorf("generate token failed: %v", err)
		return "", errors.New("login failed")
	}
	return token, err
}

func (s *UserServiceImpl) LoginByPhone(ctx context.Context, countryCode, phone int64, password string) (string, error) {
	// TODO: 手机登录
	panic("implement me")
}

func (s *UserServiceImpl) LoginByEmail(ctx context.Context, email, password string) (string, error) {
	// TODO: 邮箱登录
	panic("implement me")
}

func (s *UserServiceImpl) CheckUserStatus(ctx context.Context, id int64) (string, error) {
	return s.repo.CheckStatus(ctx, id)
}

func (s *UserServiceImpl) Update(ctx context.Context, user *domain.User) error {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) UpdatePassword(ctx context.Context, id int64, newPassword, oldPassword string) error {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) UpdatePhone(ctx context.Context, id, phone, countryCode int64) error {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) ForgetPassword(ctx context.Context, phone, email, password string) error {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) BannedUser(ctx context.Context, id int64, time time.Time) error {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) Delete(ctx context.Context, id int64) error {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) IsExistsByID(ctx context.Context, id int64) (bool, error) {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) IsExistsByPhone(ctx context.Context, phone int64) (bool, error) {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) IsExistsByEmail(ctx context.Context, email string) (bool, error) {
	//TODO implement me
	panic("implement me")
}

func (s *UserServiceImpl) CheckEmailVerificationCode(ctx context.Context, email string, verificationCode string) (bool, error) {
	if verificationCode == "" || email == "" {
		return false, errors.New("verification code or email cannot be empty")
	}
	if !utils.VerifyEmail(email) {
		return false, errors.New("email format is incorrect")
	}

	return s.repo.CheckEmailVerificationCode(ctx, email, verificationCode)
}
